﻿namespace Armon.Lib.Algorithm
{
    public class ArithmeticExpression
    {
        private const string LeftBracket = "(";
        private const string RightBracket = ")";
        private string[] operators = { "+", "-", "*", "/", ">", "<", ">=", "<=", "=", "!=", "OR", "AND" };
        private string[] necessaryOperators = { ">", "<", ">=", "<=", "=", "!=" };

        public List<string> CreatePostfix(List<string> es)
        {
            var result = new List<string>();
            var stack = new Stack<string>();

            foreach (var e in es)
            {
                if (e == LeftBracket)
                {
                    stack.Push(e);
                }
                else if (e == RightBracket)
                {
                    while (stack.Count > 0 && stack.Peek() != "(")
                    {
                        result.Add(stack.Pop());
                    }
                    if (stack.Count > 0 && stack.Peek() != "(")
                    {
                        throw new InvalidOperationException("无效的表达式");
                    }
                    else
                    {
                        stack.Pop();
                    }
                }
                else if (operators.Contains(e))
                {
                    while (stack.Count > 0 && GetPriority(e) <= GetPriority(stack.Peek()))
                    {
                        result.Add(stack.Pop());
                    }
                    stack.Push(e);
                }
                else
                {
                    result.Add(e);
                }
            }

            while (stack.Count > 0)
            {
                result.Add(stack.Pop());
            }

            return result;
        }

        public List<string> Split(string expression)
        {
            return expression.Split(" ", StringSplitOptions.RemoveEmptyEntries).Select(e => e.Trim()).ToList();
        }

        public Node CreateTree(List<string> postfix)
        {
            var stack = new Stack<Node>();
            foreach (var p in postfix)
            {
                if (operators.Contains(p))
                {
                    var right = stack.Pop();
                    var left = stack.Pop();
                    stack.Push(new Node(p, left, right));
                }
                else
                {
                    stack.Push(new Node(p));
                }

            }
            return stack.Pop();
        }

        private int GetPriority(string o)
        {
            return o switch
            {
                "OR" or "AND" => 1,
                ">" or "<" or ">=" or "<=" or "=" or "!=" => 2,
                "+" or "-" => 3,
                "*" or "/" => 4,
                _ => 0,
            };
        }
    }
}